package com.dc.aspect;

import com.dc.annotation.Permissions;
import com.dc.common.ResponseResultVO;
import com.dc.constat.SystemConstant;
import com.dc.util.RedisUtil;
import com.dc.util.TokenUtil;
import com.dc.vo.SysUserVO;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * 基于 Spring Aop 的注解鉴权
 *
 * @author kong
 */
@Aspect
@Component
public class PreAuthorizeAspect {

    @Resource
    TokenUtil tokenUtil;

    @Resource
    RedisUtil redisUtil;

    /**
     * 定义AOP签名 (切入所有使用鉴权注解的方法)
     */
    public static final String POINTCUT_SIGN = "@annotation(com.dc.annotation.Permissions)";

    /**
     * 构建
     */
    public PreAuthorizeAspect() {
    }

    /**
     * 声明AOP签名
     */
    @Pointcut(POINTCUT_SIGN)
    public void pointcut() {
    }

    /**
     * 环绕切入
     *
     * @param joinPoint 切面对象
     * @return 底层方法执行后的返回值
     * @throws Throwable 底层方法抛出的异常
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 注解鉴权
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Permissions permissions = signature.getMethod().getAnnotation(Permissions.class);
        try {
            // 执行原有逻辑
            //判断是否有权限
            // 获取当前用户token
            String token = tokenUtil.getToken();
            if (StringUtils.isBlank(token)) {
                return ResponseResultVO.failNoLoginResult("token失效");
            }
            String tokenRedisKey = "token:" + token;
            Map<Object, Object> map = this.redisUtil.hmget(tokenRedisKey);
            // Redis中会话的用户类型
            Object userType = map.get(SystemConstant.REDIS_USER_TYPE_KEY);
            // Redis中会话的用户信息对象
            Object userInfo = map.get(SystemConstant.REDIS_USER_INFO_KEY);
            if (userInfo == null) {
                return ResponseResultVO.failNoLoginResult("token失效");
            }
            // 是否不验证权限
            boolean isNotCheckPermission = false;
            if (SystemConstant.REDIS_MEMBER_USER_TYPE.equals(userType)) {
                // 会员用户
                isNotCheckPermission = true;
            } else if (SystemConstant.REDIS_SYS_USER_TYPE.equals(userType)) {
                if (userInfo instanceof SysUserVO) {
                    // 后台管理员用户
                    SysUserVO sysUser = (SysUserVO) userInfo;
                    // 判断是否是超级管理员
                    if (sysUser.getIsSuper() != null && sysUser.getIsSuper() == 1) {
                        isNotCheckPermission = true;
                    }
                }
            } else {
                // 不匹配的会话数据当做登录失效处理
                return ResponseResultVO.failNoLoginResult("token失效");
            }
            // 权限验证字符串
            String permissionStr = permissions.value();
            // 超级管理员不进行权限验证
            if (StringUtils.isBlank(permissionStr) || isNotCheckPermission) {
                return joinPoint.proceed();
            }
            // 获取用户权限字符串集合
            Object permissionObj = map.get("permission");
            if (permissionObj == null) {
                return ResponseResultVO.failNoLoginResult("权限不足，请联系管理员配置权限");
            }
            List<String> permissionList = (List<String>) permissionObj;
            if (!permissionList.contains(permissionStr)) {
                return ResponseResultVO.failNoLoginResult("权限不足");
            }
            return joinPoint.proceed();
        } catch (Throwable e) {
            throw e;
        }
    }
}
